{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T02:07:03.968724900Z",
     "start_time": "2024-05-02T02:06:51.621688600Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=9, micro=7, releaselevel='final', serial=0)\n",
      "matplotlib 3.8.4\n",
      "numpy 1.26.4\n",
      "pandas 2.2.2\n",
      "sklearn 1.4.2\n",
      "torch 2.2.2+cpu\n",
      "cpu\n"
     ]
    }
   ],
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "    \n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n",
    "torch.manual_seed(seed)\n",
    "torch.cuda.manual_seed_all(seed)\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 准备数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T02:07:23.564574200Z",
     "start_time": "2024-05-02T02:07:06.578193100Z"
    }
   },
   "outputs": [],
   "source": [
    "from tensorflow import keras\n",
    "#用karas有的数据集imdb，电影分类,分电影是积极的，还是消极的\n",
    "imdb = keras.datasets.imdb\n",
    "#载入数据使用下面两个参数\n",
    "vocab_size = 10000  #词典大小，仅保留训练数据中前10000个最经常出现的单词，低频单词被舍弃\n",
    "index_from = 3  #0,1,2,3空出来做别的事\n",
    "#前一万个词出现词频最高的会保留下来进行处理，后面的作为特殊字符处理，\n",
    "# 小于3的id都是特殊字符，下面代码有写\n",
    "# 需要注意的一点是取出来的词表还是从1开始的，需要做处理\n",
    "(train_data, train_labels), (test_data, test_labels) = imdb.load_data(\n",
    "    num_words = vocab_size, index_from = index_from)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T02:07:39.441120600Z",
     "start_time": "2024-05-02T02:07:39.402142100Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train 25000 (25000,)\n",
      "test 25000 (25000,)\n"
     ]
    }
   ],
   "source": [
    "print(\"train\", len(train_data), train_labels.shape) #25000个样本，每个样本是一段话，每个单词用一个数字表示\n",
    "print(\"test\", len(test_data), test_labels.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T02:07:43.053853100Z",
     "start_time": "2024-05-02T02:07:42.913933400Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "88584\n",
      "<class 'dict'>\n"
     ]
    }
   ],
   "source": [
    "#载入词表，看下词表长度，词表就像英语字典\n",
    "word_index = imdb.get_word_index()\n",
    "print(len(word_index))\n",
    "print(type(word_index))\n",
    "#词表虽然有8万多，但是我们只载入了最高频的1万词！！！！"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构造 word2idx 和 idx2word"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T02:08:23.378244900Z",
     "start_time": "2024-05-02T02:08:23.285299300Z"
    }
   },
   "outputs": [],
   "source": [
    "word2idx = {word: idx + 3 for word, idx in word_index.items()}\n",
    "word2idx.update({\n",
    "    \"[PAD]\": 0,     # 填充 token\n",
    "    \"[BOS]\": 1,     # begin of sentence\n",
    "    \"[UNK]\": 2,     # 未知 token\n",
    "    \"[EOS]\": 3,     # end of sentence\n",
    "})\n",
    "\n",
    "idx2word = {idx: word for word, idx in word2idx.items()}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T02:08:29.023906Z",
     "start_time": "2024-05-02T02:08:26.389451400Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 640x480 with 1 Axes>",
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAigAAAGdCAYAAAA44ojeAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA75ElEQVR4nO3deXgUVb7/8U9viYlmMYFsY9iVRQICaogLwiUKcUVwBhQdUAZEAyOgiPGqoN57w6jjMoo4jgrOKOLoZXFwxIcdl4CAICCIgCioCTAyJCyS9HJ+f3ipny3pQKBT3Q3v1/PU4+mq09XfOrSpb59TdcphjDECAACIIs5IBwAAAPBLJCgAACDqkKAAAICoQ4ICAACiDgkKAACIOiQoAAAg6pCgAACAqEOCAgAAoo470gEcj0AgoO+//15JSUlyOByRDgcAABwDY4z27dunnJwcOZ1195HEZILy/fffKzc3N9JhAACA47Bjxw6dddZZddaJyQQlKSlJ0k8HmJycHOFoAADAsaiqqlJubq51Hq9LTCYoh4d1kpOTSVBiiN/v17JlyyRJXbt2lcvlinBEAIBIOJbLM2IyQUFs8vv9mj9/viTpggsuIEEBAIREggLbOJ1OdezY0SoDABAKCQps43a71adPn0iHAQCIAfVKUEpLSzVjxgx98cUXSkhI0EUXXaQ//OEPat26tVXn0KFDuvvuuzV9+nRVV1erV69eev7555WZmWnV2b59u+644w4tWrRIZ5xxhgYNGqTS0lK53eRLAHAyMMbI5/PJ7/dHOhTYyOVyye12h2UKkHplBEuWLFFxcbEuuOAC+Xw+3X///briiiu0YcMGnX766ZKk0aNH691339Vbb72llJQUjRgxQn379tVHH30k6afrEK666iplZWXp448/Vnl5uX7729/K4/Hof/7nf074gAAAkVVTU6Py8nIdPHgw0qEgAhITE5Wdna24uLgT2o/DGGOO9827d+9WRkaGlixZom7duqmyslKNGzfWtGnTdMMNN0iSvvjiC7Vt21ZlZWXq2rWr3nvvPV199dX6/vvvrV6VF154QePGjdPu3buP6YCqqqqUkpKiyspK7uKJITU1NXryySclSWPGjDnhLy+A6BMIBLR582a5XC41btxYcXFxTKh5ijDGqKamRrt375bf79fZZ599xPWG9Tl/n9CYSmVlpSQpLS1NkrRq1Sp5vV4VFhZaddq0aaMmTZpYCUpZWZny8vKChnx69eqlO+64Q59//rk6dep0xOdUV1eruro66AARm37+7wjg5FNTU6NAIKDc3FwlJiZGOhzYLCEhQR6PR998841qamp02mmnHfe+jjtBCQQCGjVqlC6++GK1b99eklRRUaG4uDilpqYG1c3MzFRFRYVV5+fJyeHth7fVprS0VA8//PDxhooo4fF4NGLECKsM4OTFnXqnrnD92x/3XoqLi7V+/XpNnz49LIHUpaSkRJWVldayY8eOBv9MhJ/D4VB6errS09Pp8gUA1Om4EpQRI0Zozpw5WrRoUdBc+llZWaqpqdHevXuD6u/cuVNZWVlWnZ07dx6x/fC22sTHx1uzxjJ7LADgZOdwODRr1qxIhyFJmjBhgs477zzbP7deCYoxRiNGjNDMmTO1cOFCNW/ePGh7ly5d5PF4tGDBAmvdpk2btH37dhUUFEiSCgoKtG7dOu3atcuqM2/ePCUnJ6tdu3YnciyIcn6/X5988ok++eQTbj0EgCgUTYlRva5BKS4u1rRp0zR79mwlJSVZ14ykpKQoISFBKSkpGjJkiMaMGaO0tDQlJydr5MiRKigoUNeuXSVJV1xxhdq1a6dbbrlFjz32mCoqKvTAAw+ouLhY8fHx4T9CRA2/36/33ntPknTeeecx1T0AIKR69aBMnjxZlZWV6t69u7Kzs63lzTfftOo89dRTuvrqq9WvXz9169ZNWVlZmjFjhrXd5XJpzpw5crlcKigo0M0336zf/va3euSRR8J3VIhKTqdT7dq1U7t27biADkDU6d69u0aOHKlRo0bpzDPPVGZmpv7yl7/owIEDuvXWW5WUlKRWrVpZP7Skn354DRkyRM2bN1dCQoJat26tZ555xtp+6NAhnXvuuRo2bJi1buvWrUpKStIrr7xyzLHt2LFDv/nNb5Samqq0tDRdd911+vrrr63tgwcPVp8+ffTEE08oOztb6enpKi4ultfrteqUl5frqquuUkJCgpo3b65p06apWbNmevrppyVJzZo1kyRdf/31cjgc1uvD/va3v6lZs2ZKSUnRgAEDtG/fvmOO/7iYGFRZWWkkmcrKykiHAgD4mR9//NFs2LDB/Pjjj0dsq66uNtXV1SYQCFjrfD6fqa6uNl6vN6x1j8dll11mkpKSzKOPPmq+/PJL8+ijjxqXy2WKiorMiy++aL788ktzxx13mPT0dHPgwAFjjDE1NTXmoYceMitWrDBfffWVee2110xiYqJ58803rf2uXr3axMXFmVmzZhmfz2e6du1qrr/++jpjkWRmzpxpfUbbtm3NbbfdZtauXWs2bNhgbrrpJtO6dWtTXV1tjDFm0KBBJjk52QwfPtxs3LjR/OMf/zCJiYnmxRdftPZZWFhozjvvPLNs2TKzatUqc9lll5mEhATz1FNPGWOM2bVrl5FkpkyZYsrLy82uXbuMMcaMHz/enHHGGaZv375m3bp1ZunSpSYrK8vcf//9tcZe13egPudvEhQAQNjUdXKaMGGCmTBhgtm/f7+1bsmSJWbChAlm9uzZQXX/+7//20yYMMH8+9//ttaVlZWZCRMmmP/93/8NqvvYY4+ZCRMmmJ07d55Q7Jdddpm55JJLrNc+n8+cfvrp5pZbbrHWlZeXG0mmrKws5H6Ki4tNv379joixUaNGZsSIESY7O9v861//qjOWnycof/vb30zr1q2DErDq6mqTkJBg3n//fWPMTwlK06ZNjc/ns+r8+te/Nv379zfGGLNx40YjyaxYscLavnnzZiPJSlB++bmHjR8/3iQmJpqqqipr3dixY01+fn6tsYcrQeHhNwAA/J8OHTpYZZfLpfT0dOXl5VnrDs/b9fMbPSZNmqRXXnlF27dv148//qiampoj7nq5++67NWvWLD333HN67733lJ6efswxffbZZ9qyZYuSkpKC1h86dEhbt261Xp977rlB1/ZlZ2dr3bp1kn66YcXtdqtz587W9latWunMM888phiaNWsW9PnZ2dlBbdAQSFBgG6/Xq2effVaSNHLkSCZrA04xJSUlkoInarz44ovVtWvXI65Lu+eee46oe8EFF6hz585H1L3rrruOqHu8frkPh8MRtO7wHE6BQECSNH36dN1zzz364x//qIKCAiUlJenxxx/X8uXLg/aza9cuffnll3K5XNq8ebN69+59zDHt379fXbp00euvv37EtsaNG9cZ++E4T1RD7jsUEhTYxhhjXVRljv8RUABiVG3P33K5XLXe0Xeide3y0Ucf6aKLLtKdd95prft5r8Zht912m/Ly8jRkyBANHTpUhYWFatu27TF9RufOnfXmm28qIyPjuOcBa926tXw+n1avXq0uXbpIkrZs2aJ///vfQfU8Hk/UTAPBrRSwjdvt1u23367bb79dbje5MYDYd/bZZ2vlypV6//339eWXX+rBBx/UihUrgupMmjRJZWVlevXVVzVw4ED16dNHAwcOVE1NzTF9xsCBA9WoUSNdd911+uCDD7Rt2zYtXrxYv//97/Xtt98e0z7atGmjwsJCDRs2TJ988olWr16tYcOGKSEhIWhm72bNmmnBggWqqKg4InmxGwkKbON0OpWVlaWsrCxuMwZwUrj99tvVt29f9e/fX/n5+frhhx+CelO++OILjR07Vs8//7xyc3MlSc8//7z+9a9/6cEHHzymz0hMTNTSpUvVpEkT9e3bV23bttWQIUN06NChevWo/PWvf1VmZqa6deum66+/XkOHDlVSUlLQA/3++Mc/at68ecrNza314b12cpgY7Guvz+OaAQD2OXTokLZt26bmzZuf0JNs0fC+/fZb5ebmav78+erZs2fY9lvXd6A+52/62WEbv99vXVGel5fHTLIAYKOFCxdq//79ysvLU3l5ue699141a9ZM3bp1i3RotSJBgW38fr9mz54tSWrXrh0JCgDYyOv16v7779dXX32lpKQkXXTRRXr99dej9o5KEhTYxul06uyzz7bKAAD79OrVS7169Yp0GMeMBAW2cbvduummmyIdBgAgBvAzFgAARB0SFABA2MXgDaIIk3D92zPEA9t4vV698MILkqThw4dH7YVZAI7f4f+vDx48qISEhAhHg0g4ePCgpBN/9AAJCmxjjNGePXusMoCTj8vlUmpqqvUgucTExKCZSnHyMsbo4MGD2rVrl1JTU0/4Tk0SFNjG7Xbr1ltvtcoATk5ZWVmS1OBPu0V0Sk1Ntb4DJ4KzBGzjdDrVpEmTSIcBoIE5HA5lZ2crIyNDXq830uHARh6PJ2xzXJGgAAAaRKinDwPHggQFtgkEAtq4caMkqW3btkzWBgAIiTMEbOPz+fT222/r7bffls/ni3Q4AIAoRg8KbONwONS0aVOrDABAKCQosI3H49HgwYMjHQYAIAYwxAMAAKIOCQoAAIg6DPHANl6vVy+//LIkaciQIUx1DwAIiQQFtjHGaOfOnVYZAIBQSFBgG7fbrZtvvtkqAwAQCmcJ2MbpdKply5aRDgMAEAO4SBYAAEQdelBgm0AgoC1btkiSWrVqxVT3AICQOEPANj6fT2+88YbeeOMNproHANSJHhTYxuFwKCcnxyoDABAKCQps4/F4NHTo0EiHAQCIAQzxAACAqFPvBGXp0qW65pprlJOTI4fDoVmzZgVtdzgctS6PP/64VadZs2ZHbJ84ceIJHwwAADg51HuI58CBA+rYsaNuu+029e3b94jt5eXlQa/fe+89DRkyRP369Qta/8gjjwR19yclJdU3FMQYr9erv/3tb5KkW265hanuAQAh1TtBKSoqUlFRUcjtWVlZQa9nz56tHj16qEWLFkHrk5KSjqiLk5sxRjt27LDKAACE0qDXoOzcuVPvvvuuhgwZcsS2iRMnKj09XZ06ddLjjz9e522n1dXVqqqqCloQe9xut/r376/+/fsz1T0AoE4NepZ49dVXlZSUdMRQ0O9//3t17txZaWlp+vjjj1VSUqLy8nI9+eSTte6ntLRUDz/8cEOGChs4nU61adMm0mEAAGKAw5xAX7vD4dDMmTPVp0+fWre3adNGl19+uZ599tk69/PKK6/o9ttv1/79+xUfH3/E9urqalVXV1uvq6qqlJubq8rKSiUnJx9v+AAAwEZVVVVKSUk5pvN3g/WgfPDBB9q0aZPefPPNo9bNz8+Xz+fT119/rdatWx+xPT4+vtbEBbElEAho+/btkqQmTZow1T0AIKQGO0O8/PLL6tKlizp27HjUumvWrJHT6VRGRkZDhYMo4PP59Oqrr+rVV19lqnsAQJ3q3YOyf/9+64FvkrRt2zatWbNGaWlpatKkiaSfunDeeust/fGPfzzi/WVlZVq+fLl69OihpKQklZWVafTo0br55pt15plnnsChINo5HA41btzYKgMAEEq9r0FZvHixevToccT6QYMGaerUqZKkF198UaNGjVJ5eblSUlKC6n366ae688479cUXX6i6ulrNmzfXLbfcojFjxhzzME59xrAAAEB0qM/5+4Quko0UEhQAAGJPfc7fXKUIAACiDrNlwTZer1fTp0+XJA0YMICp7gEAIZGgwDbGGH311VdWGQCAUEhQYBu3263rr7/eKgMAEApnCdjG6XSqQ4cOkQ4DABADuEgWAABEHXpQYJtAIKDy8nJJUnZ2NlPdAwBC4gwB2/h8Pr300kt66aWXmOoeAFAnelBgG4fDYc0szFT3AIC6kKDANh6PR6NGjYp0GACAGMAQDwAAiDokKAAAIOowxAPb+Hw+vf3225KkG264gcnaAAAhcYaAbQKBgDZt2mSVAQAIhQQFtnG5XLr66qutMgAAoXANik2a3fdupEOIOJfLpS5duqhLly4kKACAOpGgAACAqMMQD2xjjNHu3bslSY0bN2ayNgBASPSgwDZer1eTJ0/W5MmT5fV6Ix0OACCK0YMCWyUmJkY6BABADCBBgW3i4uI0duzYSIcBAIgBDPEAAICoQ4ICAACiDkM8sI3P59M777wjSbr22muZ6h4AEBI9KLBNIBDQunXrtG7dOqa6BwDUiZ+wsI3L5VKvXr2sMgAAoZCgwDYul0tdu3aNdBgAgBjAEA8AAIg69KDANsYYVVZWSpJSUlKY6h4AEBI9KLCN1+vVM888o2eeeYap7gEAdaIHBbbyeDyRDgEAEANIUGCbuLg43X///ZEOAwAQAxjiAQAAUYcEBQAARJ16JyhLly7VNddco5ycHDkcDs2aNSto++DBg+VwOIKW3r17B9XZs2ePBg4cqOTkZKWmpmrIkCHav3//CR0Iot/hqe7feecd+Xy+SIcDAIhi9U5QDhw4oI4dO2rSpEkh6/Tu3Vvl5eXW8sYbbwRtHzhwoD7//HPNmzdPc+bM0dKlSzVs2LD6R4+YEggEtHr1aq1evZqp7gEAdar3RbJFRUUqKiqqs058fLyysrJq3bZx40bNnTtXK1as0Pnnny9JevbZZ3XllVfqiSeeUE5OTn1DQoxwuVzq0aOHVQYAIJQGuQZl8eLFysjIUOvWrXXHHXfohx9+sLaVlZUpNTXVSk4kqbCwUE6nU8uXL691f9XV1aqqqgpaEHtcLpe6deumbt26kaAAAOoU9gSld+/e+utf/6oFCxboD3/4g5YsWaKioiL5/X5JUkVFhTIyMoLe43a7lZaWpoqKilr3WVpaqpSUFGvJzc0Nd9gAACCKhH0elAEDBljlvLw8dejQQS1bttTixYvVs2fP49pnSUmJxowZY72uqqoiSYlBxhgdPHhQkpSYmMhU9wCAkBr8NuMWLVqoUaNG2rJliyQpKytLu3btCqrj8/m0Z8+ekNetxMfHKzk5OWhB7PF6vXriiSf0xBNPMNU9AKBODZ6gfPvtt/rhhx+UnZ0tSSooKNDevXu1atUqq87ChQsVCASUn5/f0OFEXLP73o10CAAARL16D/Hs37/f6g2RpG3btmnNmjVKS0tTWlqaHn74YfXr109ZWVnaunWr7r33XrVq1Uq9evWSJLVt21a9e/fW0KFD9cILL8jr9WrEiBEaMGAAd/Cc5OLi4jR+/PhIhwEAiAH17kFZuXKlOnXqpE6dOkmSxowZo06dOumhhx6Sy+XS2rVrde211+qcc87RkCFD1KVLF33wwQeKj4+39vH666+rTZs26tmzp6688kpdcsklevHFF8N3VAAAIKbVuwele/fuMsaE3P7+++8fdR9paWmaNm1afT8aAACcIniaMWzj8/k0f/58ST/NfeN28/UDANSOhwXCNoFAQMuXL9fy5cuZ6h4AUCd+wsI2LpdLl1xyiVUGACAUEhTYxuVyHfdkfQCAUwtDPAAAIOrQgwLbGGOsGWQ9Hg9T3QMAQqIHBbbxer0qLS1VaWkpU90DAOpEgtLAmNoeAID6Y4gHtvF4PCopKbHKAACEQoIC2zgcDsXFxUU6DABADGCIBwAARB0SlAg5Fa9N8fv9WrBggRYsWCC/3x/pcAAAUYwEBbbx+/368MMP9eGHH5KgAADqxDUosI3T6VR+fr5VBgAgFBIU2Mbtdqt3796RDgMAEAP4GQsAAKIOCQoAAIg6DPHANjU1NSotLZUklZSUMCcKACAkelAAAEDUoQcFtvF4PLrnnnusMgAAoZCgwDYOh0Onn356pMMAAMQAhngAAEDUoQcFtvH7/froo48kSRdffLFcLleEIwIARCsSFNjG7/dr0aJFkqSuXbuSoAAAQiJBgW2cTqc6depklQEACIUEBbZxu9269tprIx0GACAG8DMWAABEHRIUAAAQdRjigW1qamr0xBNPSJLuueceproHAIREggJbeb3eSIcAAIgBJCiwjcfj0V133WWVAQAIhQQFtnE4HEpNTY10GACAGMBFsgAAIOrQgwLb+P1+rVixQpJ0wQUXMJMsACCkevegLF26VNdcc41ycnLkcDg0a9Ysa5vX69W4ceOUl5en008/XTk5Ofrtb3+r77//PmgfzZo1k8PhCFomTpx4wgeD6Ob3+/X+++/r/fffl9/vj3Q4AIAoVu8E5cCBA+rYsaMmTZp0xLaDBw/q008/1YMPPqhPP/1UM2bM0KZNm2qdPfSRRx5ReXm5tYwcOfL4jgAxw+l0Ki8vT3l5eUx1DwCoU72HeIqKilRUVFTrtpSUFM2bNy9o3XPPPacLL7xQ27dvV5MmTaz1SUlJysrKqu/HI4a53W717ds30mEAAGJAg/+MraysrPXujYkTJyo9PV2dOnXS448/Lp/PF3If1dXVqqqqCloAAMDJq0Evkj106JDGjRunG2+8UcnJydb63//+9+rcubPS0tL08ccfq6SkROXl5XryySdr3U9paakefvjhhgwVAABEkQZLULxer37zm9/IGKPJkycHbRszZoxV7tChg+Li4nT77bertLRU8fHxR+yrpKQk6D1VVVXKzc1tqNDRQGpqavTMM89Iku666y6mugcAhNQgCcrh5OSbb77RwoULg3pPapOfny+fz6evv/5arVu3PmJ7fHx8rYkLYs/BgwcjHQIAIAaEPUE5nJxs3rxZixYtUnp6+lHfs2bNGjmdTmVkZIQ7HEQRj8ejO+64wyoDABBKvROU/fv3a8uWLdbrbdu2ac2aNUpLS1N2drZuuOEGffrpp5ozZ478fr8qKiokSWlpaYqLi1NZWZmWL1+uHj16KCkpSWVlZRo9erRuvvlmnXnmmeE7MkQdh8NBEgoAOCb1TlBWrlypHj16WK8PXxsyaNAgTZgwQe+8844k6bzzzgt636JFi9S9e3fFx8dr+vTpmjBhgqqrq9W8eXONHj066BoTAABwaqt3gtK9e3cZY0Jur2ubJHXu3FnLli2r78fiJOD3+7VmzRpJPyWwTHUPAAiFZ/HANn6/X3PmzJEk5eXlkaAAAEIiQYFtnE6ndZcWU90DAOpCggLbuN1uDRgwINJhAABiAD9jAQBA1CFBAQAAUYchHtjG6/Vq0qRJkqTi4mImawMAhESCAtsYY1RZWWmVAQAIhQQFtnG73frd735nlQEACIWzBGzjdDr1q1/9KtJhAABiABfJAgCAqEMPCmwTCAS0fv16SVL79u2ZrA0AEBIJCmzj8/k0c+ZMSVKbNm0UFxcX4YgAANGKBAW2cTgcatGihVUGACAUEhTYxuPx6JZbbol0GACAGMBFAAAAIOqQoAAAgKjDEA9s4/V69Ze//EWSNHToUKa6BwCERIIC2xhjtHv3bqsMAEAoJCiwjdvt1qBBg6wyAAChcJaAbZxOp5o1axbpMAAAMYCLZAEAQNShBwW2CQQC+vLLLyVJ55xzDlPdAwBC4gwB2/h8Pr355pt688035fP5Ih0OACCK0YMC2zgcDuXm5lplAABCIUGBbTwej2677bZIhwEAiAEM8QAAgKhDggIAAKIOQzywjdfr1dSpUyVJgwcPZqp7AEBIJCiwjTFG33//vVUGACAUEhTYxu1268Ybb7TKAACEwlkCtnE6nTrnnHMiHQYAIAZwkSwAAIg69KDANoFAQNu2bZMkNW/enKnuAQAhcYaAbXw+n1577TW99tprTHUPAKhTvROUpUuX6pprrlFOTo4cDodmzZoVtN0Yo4ceekjZ2dlKSEhQYWGhNm/eHFRnz549GjhwoJKTk5WamqohQ4Zo//79J3QgiH4Oh0OZmZnKzMxkqnsAQJ3qnaAcOHBAHTt21KRJk2rd/thjj+lPf/qTXnjhBS1fvlynn366evXqpUOHDll1Bg4cqM8//1zz5s3TnDlztHTpUg0bNuz4jwIxwePxaPjw4Ro+fDhzoAAA6lTva1CKiopUVFRU6zZjjJ5++mk98MADuu666yRJf/3rX5WZmalZs2ZpwIAB2rhxo+bOnasVK1bo/PPPlyQ9++yzuvLKK/XEE08oJyfnBA4HAACcDMJ6Dcq2bdtUUVGhwsJCa11KSory8/NVVlYmSSorK1NqaqqVnEhSYWGhnE6nli9fXut+q6urVVVVFbQAAICTV1gTlIqKCklSZmZm0PrMzExrW0VFhTIyMoK2u91upaWlWXV+qbS0VCkpKdaSm5sbzrBhk8NT3U+dOlVerzfS4QAAolhM3MVTUlKiyspKa9mxY0ekQ8JxMMbom2++0TfffMNU9wCAOoV1HpSsrCxJ0s6dO5WdnW2t37lzp8477zyrzq5du4Le5/P5tGfPHuv9vxQfH6/4+PhwhooIcLvduuGGG6wyAAChhLUHpXnz5srKytKCBQusdVVVVVq+fLkKCgokSQUFBdq7d69WrVpl1Vm4cKECgYDy8/PDGQ6ijNPp1Lnnnqtzzz2XSdoAAHWq98/Y/fv3a8uWLdbrbdu2ac2aNUpLS1OTJk00atQo/dd//ZfOPvtsNW/eXA8++KBycnLUp08fSVLbtm3Vu3dvDR06VC+88IK8Xq9GjBihAQMGcAcPAACQdBwJysqVK9WjRw/r9ZgxYyRJgwYN0tSpU3XvvffqwIEDGjZsmPbu3atLLrlEc+fO1WmnnWa95/XXX9eIESPUs2dPOZ1O9evXT3/605/CcDiIZoFAQN9++60k6ayzzqIXBQAQUr0TlO7du9d5gaPD4dAjjzyiRx55JGSdtLQ0TZs2rb4fjRjn8/k0ZcoUST9d+BwXFxfhiAAA0YorFWEbh8OhtLQ0qwwAQCgkKLCNx+PRyJEjIx0GACAGcBFAlGh237uRDgEAgKhBggIAAKIOQzywjc/n09///ndJ0m9+8xsmawMAhEQPSoT9cmjnZB7qCQQC2rx5szZv3qxAIBDpcAAAUYyfsLCNy+XSddddZ5UBAAiFBAW2cblc1jOZAACoC0M8AAAg6tCDAtsEAgHrSdYZGRlMdQ8ACIkzBGzj8/n05z//WX/+85/l8/kiHQ4AIIrRgwLbOBwOJSUlWWUAAEIhQYFtPB6P9fRrAADqwhAPAACIOiQoAAAg6jDEA9v4fD7NnDlTknT99dcz1T0AICR6UGCbQCCgDRs2aMOGDUx1DwCoEz9hYRuXy6WioiKrDABAKCQosI3L5dKFF14Y6TAAADGAIR4AABB16EGBbYwx2rNnjyQpLS2NydoAACHRgwLbeL1ePffcc3ruuefk9XojHQ4AIIrRgwJbxcfHRzoEAEAMIEGBbeLi4nTfffdFOgwAQAxgiAcAAEQdEhQAABB1GOKBbXw+n+bMmSNJuvrqq5nqHgAQEj0osE0gENBnn32mzz77jKnuAQB14icsbONyuVRYWGiVAQAIhQQFtnG5XLr44osjHQYAIAYwxAMAAKIOPSiwjTFG+/btkyQlJSUx1T0AICR6UKJUs/vejXQIYef1evXUU0/pqaeeYqp7AECdwp6gNGvWTA6H44iluLhYktS9e/cjtg0fPjzcYSBKOZ1OOZ3kxQCAuoV9iGfFihXy+/3W6/Xr1+vyyy/Xr3/9a2vd0KFD9cgjj1ivExMTwx0GolBcXJwefPDBSIcBAIgBYU9QGjduHPR64sSJatmypS677DJrXWJiorKyssL90QAA4CTRoH3tNTU1eu2113TbbbcFXRD5+uuvq1GjRmrfvr1KSkp08ODBhgwDAADEmAa9i2fWrFnau3evBg8ebK276aab1LRpU+Xk5Gjt2rUaN26cNm3apBkzZoTcT3V1taqrq63XVVVVDRk2GojP59P7778vSerVqxdT3QMAQmrQM8TLL7+soqIi5eTkWOuGDRtmlfPy8pSdna2ePXtq69atatmyZa37KS0t1cMPP9yQocIGgUBAK1eulCRdfvnlEY4GABDNGmyI55tvvtH8+fP1u9/9rs56+fn5kqQtW7aErFNSUqLKykpr2bFjR1hjhT1cLpcuu+wyXXbZZUx1DwCoU4P1oEyZMkUZGRm66qqr6qy3Zs0aSVJ2dnbIOvHx8YqPjw9neIgAl8ul7t27RzoMAEAMaJAEJRAIaMqUKRo0aFDQdQZbt27VtGnTdOWVVyo9PV1r167V6NGj1a1bN3Xo0KEhQgEAADGoQRKU+fPna/v27brtttuC1sfFxWn+/Pl6+umndeDAAeXm5qpfv3564IEHGiIMRBljjHWxc3x8PFPdAwBCapAE5YorrpAx5oj1ubm5WrJkSUN8JGKA1+vVH/7wB0k/XVcUFxcX4YgAANGKOccBAEDUYSIK2Mbj8VjDeTyPBwBQFxIU2MbhcHB7MQDgmPAztoE0u+/dqNgHAACxiB4U2Mbv92vBggWSpJ49e9KbAgAIiR4U2Mbv96usrExlZWXy+/2RDgcAEMVIUGLAyTLU43K5VFBQoIKCAnpPAAB1YogHtnG5XLriiisiHQYAIAbQgwIAAKIOPSiwjTFGgUBA0k/zoDDVPQAgFBIU2Mbr9aq0tFQSU90DAOrGEA8AAIg69KBEuZPlDh7pp6nux40bZ5UBAAiFBAW2cTgcOu200yIdBgAgBjDEAwAAog49KLCN3+/XBx98IEm69NJLmawNABASCQps4/f7tWTJEknSRRddRIICAAiJBAW2cTqdOv/8860yAAChkKDANm63W1dddVWkwwAAxAB+xsaok+n2YwAAfokEBQAARB0SlBgS670mNTU1evTRR/Xoo4+qpqYm0uEAAKIYCUqMifUkJRAIWA8MBAAgFC6ShW08Ho9Gjx5tlQEACIUEBbZxOBxKTk6OdBgAgBjAEA8AAIg69KDANn6/X8uWLZMkde3alZlkAQAhkaDANn6/X/Pnz5ckXXDBBSQoAICQSFBgG6fTqY4dO1plAABCIUGBbdxut/r06RPpMAAAMYCfsTEo1udCAQDgaEhQYgRJCQDgVMIQD2xTU1OjJ598UpI0ZswYxcXFRTgiAEC0ogclxh3uWYmVHpbq6mpVV1dHOgwAQJQLe4IyYcIEORyOoKVNmzbW9kOHDqm4uFjp6ek644wz1K9fP+3cuTPcYSAKeTwejRgxQiNGjGCqewBAnRqkB+Xcc89VeXm5tXz44YfWttGjR+sf//iH3nrrLS1ZskTff/+9+vbt2xBhIMo4HA6lp6crPT1dDocj0uEAAKJYg1yD4na7lZWVdcT6yspKvfzyy5o2bZr+4z/+Q5I0ZcoUtW3bVsuWLVPXrl0bIhwAABBjGqQHZfPmzcrJyVGLFi00cOBAbd++XZK0atUqeb1eFRYWWnXbtGmjJk2aqKysLOT+qqurVVVVFbREWrRe8xGtcUk/zST7ySef6JNPPpHf7490OACAKBb2BCU/P19Tp07V3LlzNXnyZG3btk2XXnqp9u3bp4qKCsXFxSk1NTXoPZmZmaqoqAi5z9LSUqWkpFhLbm5uuMOGDfx+v9577z299957JCgAgDqFfYinqKjIKnfo0EH5+flq2rSp/v73vyshIeG49llSUqIxY8ZYr6uqqkhSYpDT6VS7du2sMgAAoTT4PCipqak655xztGXLFl1++eWqqanR3r17g3pRdu7cWes1K4fFx8crPj6+oUM9ZtEyjBItcRwrt9utX//615EOAwAQAxr8Z+z+/fu1detWZWdnq0uXLvJ4PFqwYIG1fdOmTdq+fbsKCgoaOhQAABAjwt6Dcs899+iaa65R06ZN9f3332v8+PFyuVy68cYblZKSoiFDhmjMmDFKS0tTcnKyRo4cqYKCAu7gAQAAlrAnKN9++61uvPFG/fDDD2rcuLEuueQSLVu2TI0bN5YkPfXUU3I6nerXr5+qq6vVq1cvPf/88+EOA1HI6/Xq2WeflSSNHDmSydoAACGFPUGZPn16ndtPO+00TZo0SZMmTQr3RyPKGWO0b98+qwwAQCg8LBC2cbvduv32260yAAChcJaAbZxOZ513awEAcBiTUQAAgKhDDwps4/f7tW7dOklSXl6eXC5XhCMCAEQrEhTYxu/3a/bs2ZKkdu3akaAAAEIiQYFtnE6nzj77bKsMAEAoJCj1FGvTy0cTt9utm266KdJhAABiAD9jAQBA1CFBOUH0qAAAEH4M8cA2Xq9XL7zwgiRp+PDhTHUPAAiJBAW2McZoz549VhkAgFBIUMKs2X3v6uuJV0U6jKjkdrt16623WmUAAELhLAHbOJ1ONWnSJNJhAABiABfJnuS4iBcAEIvoQYFtAoGANm7cKElq27Ytk7UBAELiDAHb+Hw+vf3223r77bfl8/kiHQ4AIIrRgwLbOBwONW3a1CoDABAKCQps4/F4NHjw4EiHAQCIAQzxAACAqEOCchKq7c6dZve9yx09AICYwRDPSSBWEg+v16uXX35ZkjRkyBCmugcAhESCAtsYY7Rz506rDABAKCQoJ5Gf96RE45T7brdbN998s1UGACAUzhKwjdPpVMuWLSMdBgAgBnCRbD3EyrUeAADEOnpQYJtAIKAtW7ZIklq1asVU9wCAkDhDHKNY7j05ltjtOD6fz6c33nhDb7zxBlPdAwDqRA8KbONwOJSTk2OVAQAIhQQFtvF4PBo6dGikwwAAxACGeE5RsTxkBQA4+ZGgAACAqEOCEiYnU49EQx2L1+vVK6+8oldeeUVer7dBPgMAcHLgGhTYxhijHTt2WGUAAEIhQYFt3G63+vfvb5UBAAgl7EM8paWluuCCC5SUlKSMjAz16dNHmzZtCqrTvXt3ORyOoGX48OHhDgVRxul0qk2bNmrTpg2TtAEA6hT2s8SSJUtUXFysZcuWad68efJ6vbriiit04MCBoHpDhw5VeXm5tTz22GPhDgUAAMSosPezz507N+j11KlTlZGRoVWrVqlbt27W+sTERGVlZYX74xHFAoGAtm/fLklq0qQJvSgAgJAa/AxRWVkpSUpLSwta//rrr6tRo0Zq3769SkpKdPDgwZD7qK6uVlVVVdCCo6vtbpxI3m3k8/n06quv6tVXX2WqewBAnRr0SsVAIKBRo0bp4osvVvv27a31N910k5o2baqcnBytXbtW48aN06ZNmzRjxoxa91NaWqqHH364IUM9pUQqSXE4HGrcuLFVBgAglAZNUIqLi7V+/Xp9+OGHQeuHDRtmlfPy8pSdna2ePXtq69atatmy5RH7KSkp0ZgxY6zXVVVVys3NbbjA0SA8Ho/uvPPOSIcBAIgBDZagjBgxQnPmzNHSpUt11lln1Vk3Pz9fkrRly5ZaE5T4+HjFx8c3SJynssM9KV9PvCrCkQAAECzsCYoxRiNHjtTMmTO1ePFiNW/e/KjvWbNmjSQpOzs73OEAAIAYFPYEpbi4WNOmTdPs2bOVlJSkiooKSVJKSooSEhK0detWTZs2TVdeeaXS09O1du1ajR49Wt26dVOHDh3CHQ6iiNfr1fTp0yVJAwYMkMfjiXBEAIBoFfYEZfLkyZJ+mozt56ZMmaLBgwcrLi5O8+fP19NPP60DBw4oNzdX/fr10wMPPBDuUBBljDH66quvrDIAAKE0yBBPXXJzc7VkyZJwfyzCoNl971rXo/y8HC5ut1vXX3+9VQYAIBTOErCN0+lkGA8AcEyYyhNB86JEciI3AAAOI0HBUR1r0nK0eoFAQN99952+++47BQKBcIQGADhJkaDANj6fTy+99JJeeuklproHANSJBAX1drinpL7DQQ6HQykpKUpJSWGqewBAnbhIFrbxeDwaNWpUpMMAAMQAelAAAEDUIUEBAABRhwQFdQrnLcg+n0/Tp0/X9OnTuUgWAFAnrkGBbQKBgDZt2mSVAQAIhQQFIYV70jaXy6Wrr77aKgMAEAoJCmzjcrnUpUuXSIcBAIgBXIMCAACiDj0ox4Dn04SHMUa7d++WJDVu3JjJ2gAAIdGDAtt4vV5NnjxZkydPltfrjXQ4AIAoRoKCBlNbz1NiYqISExMjEA0AIJYwxAPbxMXFaezYsZEOAwAQA+hBAQAAUYcEBQAARB0SFJywY73LyefzacaMGZoxYwZT3QMA6kSCAtsEAgGtW7dO69atq3Wqe27nBgAcRoIC27hcLvXq1UvLa3KZ6h4AUCcSFNim5X/OVdeuXbXBnymXy3XcPSbN7nuX3hYAOMmRoAAAgKhDgoKw+2Xvxv9/bbR3716d4aiWMea49nW8delxAYDYQoIC27gV0DPPPKNfn7aOqe4BAHUiQYGtPB6PvObIr92x9nDU1jsT6r30mgBA7CJBgW18cun+++/Xa4c6Ky4uLtLhAACiGAkKIu7nPR2He0R+2TNyInf8nMh2AEBkkKDUgZNX7DnaLcj1TVj4DgBAZPA0Y9jGqYDeeecdXeTZwVT3AIA60YMC2zhltHr1arV2/6vWqe5DOdyLUVfvxvHcjlzX+0+05+RY3n+8Fwbb+dkAECkkKLBNQA716NFDq7w5THUPAKgTCcpR8EszfAJyqlu3blrra/gE5Wi9K/XtfQnVi3MicdWn7ol8frhiBwA7RTRBmTRpkpo1a6bTTjtN+fn5+uSTTyIZDgAAiBIRS1DefPNNjRkzRuPHj9enn36qjh07qlevXtq1a1ekQgrCr82GYHTgwAHFy3vMU91Hq4a42+d4enpquyW7rvfyvQYQKyKWoDz55JMaOnSobr31VrVr104vvPCCEhMT9corr0QqJAt/xBuGWwE98cQTuinhs4hMdd8Qc6IcLVE52gW5x5s41JaUhFp3tJjr+oyG1FBPpQ7Hv2O4hGu//E2C3aLhOxeR24xramq0atUqlZSUWOucTqcKCwtVVlZ2RP3q6mpVV1dbrysrKyVJVVVVDRJfoPrgMdWrqqpSoPpgg/03moTrmA45DtW6v2hix79rXeXDQrXLsbTZsdapy+GYG0ptxxyu/dZ3nw11rOHab0P/WwC/1FDfucP7PKZedBMB3333nZFkPv7446D1Y8eONRdeeOER9cePH28ksbCwsLCwsJwEy44dO46aK8TERG0lJSUaM2aM9ToQCGjPnj1KT0+Xw+EIy2dUVVUpNzdXO3bsUHJyclj2iSPRzvahre1DW9uHtrZPQ7S1MUb79u1TTk7OUetGJEFp1KiRXC6Xdu7cGbR+586dysrKOqJ+fHy84uPjg9alpqY2SGzJycl86W1AO9uHtrYPbW0f2to+4W7rlJSUY6oXkYtk4+Li1KVLFy1YsMBaFwgEtGDBAhUUFEQiJAAAEEUiNsQzZswYDRo0SOeff74uvPBCPf300zpw4IBuvfXWSIUEAACiRMQSlP79+2v37t166KGHVFFRofPOO09z585VZmZmROKJj4/X+PHjjxhKQnjRzvahre1DW9uHtrZPpNvaYUyMz5gFAABOOjyLBwAARB0SFAAAEHVIUAAAQNQhQQEAAFGHBEXSpEmT1KxZM5122mnKz8/XJ598EumQYsqECRPkcDiCljZt2ljbDx06pOLiYqWnp+uMM85Qv379jpikb/v27brqqquUmJiojIwMjR07Vj6fz+5DiTpLly7VNddco5ycHDkcDs2aNStouzFGDz30kLKzs5WQkKDCwkJt3rw5qM6ePXs0cOBAJScnKzU1VUOGDNH+/fuD6qxdu1aXXnqpTjvtNOXm5uqxxx5r6EOLOkdr68GDBx/xPe/du3dQHdr66EpLS3XBBRcoKSlJGRkZ6tOnjzZt2hRUJ1x/MxYvXqzOnTsrPj5erVq10tSpUxv68KLKsbR19+7dj/heDx8+PKhOxNo6LA/XiWHTp083cXFx5pVXXjGff/65GTp0qElNTTU7d+6MdGgxY/z48ebcc8815eXl1rJ7925r+/Dhw01ubq5ZsGCBWblypenatau56KKLrO0+n8+0b9/eFBYWmtWrV5t//vOfplGjRqakpCQShxNV/vnPf5r//M//NDNmzDCSzMyZM4O2T5w40aSkpJhZs2aZzz77zFx77bWmefPm5scff7Tq9O7d23Ts2NEsW7bMfPDBB6ZVq1bmxhtvtLZXVlaazMxMM3DgQLN+/XrzxhtvmISEBPPnP//ZrsOMCkdr60GDBpnevXsHfc/37NkTVIe2PrpevXqZKVOmmPXr15s1a9aYK6+80jRp0sTs37/fqhOOvxlfffWVSUxMNGPGjDEbNmwwzz77rHG5XGbu3Lm2Hm8kHUtbX3bZZWbo0KFB3+vKykpreyTb+pRPUC688EJTXFxsvfb7/SYnJ8eUlpZGMKrYMn78eNOxY8dat+3du9d4PB7z1ltvWes2btxoJJmysjJjzE8nBqfTaSoqKqw6kydPNsnJyaa6urpBY48lvzxpBgIBk5WVZR5//HFr3d69e018fLx54403jDHGbNiwwUgyK1assOq89957xuFwmO+++84YY8zzzz9vzjzzzKC2HjdunGndunUDH1H0CpWgXHfddSHfQ1sfn127dhlJZsmSJcaY8P3NuPfee825554b9Fn9+/c3vXr1auhDilq/bGtjfkpQ7rrrrpDviWRbn9JDPDU1NVq1apUKCwutdU6nU4WFhSorK4tgZLFn8+bNysnJUYsWLTRw4EBt375dkrRq1Sp5vd6gNm7Tpo2aNGlitXFZWZny8vKCJunr1auXqqqq9Pnnn9t7IDFk27ZtqqioCGrblJQU5efnB7Vtamqqzj//fKtOYWGhnE6nli9fbtXp1q2b4uLirDq9evXSpk2b9O9//9umo4kNixcvVkZGhlq3bq077rhDP/zwg7WNtj4+lZWVkqS0tDRJ4fubUVZWFrSPw3VO5b/tv2zrw15//XU1atRI7du3V0lJiQ4ePGhti2Rbx8TTjBvKv/71L/n9/iNmr83MzNQXX3wRoahiT35+vqZOnarWrVurvLxcDz/8sC699FKtX79eFRUViouLO+LhjpmZmaqoqJAkVVRU1PpvcHgbane4bWpru5+3bUZGRtB2t9uttLS0oDrNmzc/Yh+Ht5155pkNEn+s6d27t/r27avmzZtr69atuv/++1VUVKSysjK5XC7a+jgEAgGNGjVKF198sdq3by9JYfubEapOVVWVfvzxRyUkJDTEIUWt2tpakm666SY1bdpUOTk5Wrt2rcaNG6dNmzZpxowZkiLb1qd0goLwKCoqssodOnRQfn6+mjZtqr///e+n3B8BnLwGDBhglfPy8tShQwe1bNlSixcvVs+ePSMYWewqLi7W+vXr9eGHH0Y6lJNeqLYeNmyYVc7Ly1N2drZ69uyprVu3qmXLlnaHGeSUHuJp1KiRXC7XEVeH79y5U1lZWRGKKvalpqbqnHPO0ZYtW5SVlaWamhrt3bs3qM7P2zgrK6vWf4PD21C7w21T1/c3KytLu3btCtru8/m0Z88e2v8EtWjRQo0aNdKWLVsk0db1NWLECM2ZM0eLFi3SWWedZa0P19+MUHWSk5NPuR9Oodq6Nvn5+ZIU9L2OVFuf0glKXFycunTpogULFljrAoGAFixYoIKCgghGFtv279+vrVu3Kjs7W126dJHH4wlq402bNmn79u1WGxcUFGjdunVBf9znzZun5ORktWvXzvb4Y0Xz5s2VlZUV1LZVVVVavnx5UNvu3btXq1atsuosXLhQgUDA+kNUUFCgpUuXyuv1WnXmzZun1q1bn3JDDvXx7bff6ocfflB2drYk2vpYGWM0YsQIzZw5UwsXLjxiyCtcfzMKCgqC9nG4zqn0t/1obV2bNWvWSFLQ9zpibX1Cl9ieBKZPn27i4+PN1KlTzYYNG8ywYcNMampq0BXLqNvdd99tFi9ebLZt22Y++ugjU1hYaBo1amR27dpljPnplsEmTZqYhQsXmpUrV5qCggJTUFBgvf/wbWxXXHGFWbNmjZk7d65p3LgxtxkbY/bt22dWr15tVq9ebSSZJ5980qxevdp88803xpifbjNOTU01s2fPNmvXrjXXXXddrbcZd+rUySxfvtx8+OGH5uyzzw669XXv3r0mMzPT3HLLLWb9+vVm+vTpJjEx8ZS69dWYutt637595p577jFlZWVm27ZtZv78+aZz587m7LPPNocOHbL2QVsf3R133GFSUlLM4sWLg25tPXjwoFUnHH8zDt/6OnbsWLNx40YzadKkU+4246O19ZYtW8wjjzxiVq5cabZt22Zmz55tWrRoYbp162btI5JtfconKMYY8+yzz5omTZqYuLg4c+GFF5ply5ZFOqSY0r9/f5OdnW3i4uLMr371K9O/f3+zZcsWa/uPP/5o7rzzTnPmmWeaxMREc/3115vy8vKgfXz99demqKjIJCQkmEaNGpm7777beL1euw8l6ixatMhIOmIZNGiQMeanW40ffPBBk5mZaeLj403Pnj3Npk2bgvbxww8/mBtvvNGcccYZJjk52dx6661m3759QXU+++wzc8kll5j4+Hjzq1/9ykycONGuQ4wadbX1wYMHzRVXXGEaN25sPB6Padq0qRk6dOgRP2Ro66OrrY0lmSlTplh1wvU3Y9GiRea8884zcXFxpkWLFkGfcSo4Wltv377ddOvWzaSlpZn4+HjTqlUrM3bs2KB5UIyJXFs7/u8gAAAAosYpfQ0KAACITiQoAAAg6pCgAACAqEOCAgAAog4JCgAAiDokKAAAIOqQoAAAgKhDggIAAKIOCQoAAIg6JCgAACDqkKAAAICoQ4ICAACizv8DYQYh8RY+gfIAAAAASUVORK5CYII="
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 选择 max_length\n",
    "length_collect = {}\n",
    "for text in train_data:\n",
    "    length = len(text)\n",
    "    length_collect[length] = length_collect.get(length, 0) + 1\n",
    "    \n",
    "MAX_LENGTH = 500\n",
    "plt.bar(length_collect.keys(), length_collect.values())\n",
    "plt.axvline(MAX_LENGTH, label=\"max length\", c=\"gray\", ls=\":\")\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tokenizer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T02:08:36.007136600Z",
     "start_time": "2024-05-02T02:08:35.952167Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "raw text\n",
      "['hello', 'world']\n",
      "['tokenize', 'text', 'datas', 'with', 'batch']\n",
      "['this', 'is', 'a', 'test']\n",
      "indices\n",
      "tensor([   0,    0,    0,    1, 4825,  182,    3])\n",
      "tensor([    1,     2,  3004,     2,    19, 19233,     3])\n",
      "tensor([   0,    1,   14,    9,    6, 2181,    3])\n",
      "decode text\n",
      "[PAD] [PAD] [PAD] [BOS] hello world [EOS]\n",
      "[BOS] [UNK] text [UNK] with batch [EOS]\n",
      "[PAD] [BOS] this is a test [EOS]\n"
     ]
    }
   ],
   "source": [
    "class Tokenizer:\n",
    "    def __init__(self, word2idx, idx2word, max_length=500, pad_idx=0, bos_idx=1, eos_idx=3, unk_idx=2):\n",
    "        self.word2idx = word2idx\n",
    "        self.idx2word = idx2word\n",
    "        self.max_length = max_length\n",
    "        self.pad_idx = pad_idx\n",
    "        self.bos_idx = bos_idx\n",
    "        self.eos_idx = eos_idx\n",
    "        self.unk_idx = unk_idx\n",
    "    \n",
    "    def encode(self, text_list, padding_first=False):\n",
    "        \"\"\"如果padding_first == True，则padding加载前面，否则加载后面\"\"\"\n",
    "        max_length = min(self.max_length, 2 + max([len(text) for text in text_list]))\n",
    "        indices_list = []\n",
    "        for text in text_list:\n",
    "            indices = [self.bos_idx] + [self.word2idx.get(word, self.unk_idx) for word in text[:max_length-2]] + [self.eos_idx]\n",
    "            if padding_first:\n",
    "                indices = [self.pad_idx] * (max_length - len(indices)) + indices\n",
    "            else:\n",
    "                indices = indices + [self.pad_idx] * (max_length - len(indices))\n",
    "            indices_list.append(indices)\n",
    "        return torch.tensor(indices_list)\n",
    "    \n",
    "    \n",
    "    def decode(self, indices_list, remove_bos=True, remove_eos=True, remove_pad=True, split=False):\n",
    "        text_list = []\n",
    "        for indices in indices_list:\n",
    "            text = []\n",
    "            for index in indices:\n",
    "                word = self.idx2word.get(index, \"[UNK]\")\n",
    "                if remove_bos and word == \"[BOS]\":\n",
    "                    continue\n",
    "                if remove_eos and word == \"[EOS]\":\n",
    "                    break\n",
    "                if remove_pad and word == \"[PAD]\":\n",
    "                    break\n",
    "                text.append(word)\n",
    "            text_list.append(\" \".join(text) if not split else text)\n",
    "        return text_list\n",
    "    \n",
    "\n",
    "tokenizer = Tokenizer(word2idx=word2idx, idx2word=idx2word)\n",
    "raw_text = [\"hello world\".split(), \"tokenize text datas with batch\".split(), \"this is a test\".split()]\n",
    "indices = tokenizer.encode(raw_text, padding_first=True)\n",
    "decode_text = tokenizer.decode(indices.tolist(), remove_bos=False, remove_eos=False, remove_pad=False)\n",
    "print(\"raw text\")\n",
    "for raw in raw_text:\n",
    "    print(raw)\n",
    "print(\"indices\")\n",
    "for index in indices:\n",
    "    print(index)\n",
    "print(\"decode text\")\n",
    "for decode in decode_text:\n",
    "    print(decode)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-12-07T09:04:16.534768400Z",
     "start_time": "2023-12-07T09:04:16.485804300Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": "[\"[BOS] this film was just brilliant casting location scenery story direction everyone's really suited the part they played and you could just imagine being there robert [UNK] is an amazing actor and now the same being director [UNK] father came from the same scottish island as myself so i loved the fact there was a real connection with this film the witty remarks throughout the film were great it was just brilliant so much that i bought the film as soon as it was released for [UNK] and would recommend it to everyone to watch and the fly fishing was amazing really cried at the end it was so sad and you know what they say if you cry at a film it must have been good and this definitely was also [UNK] to the two little boy's that played the [UNK] of norman and paul they were just brilliant children are often left out of the [UNK] list i think because the stars that play them all grown up are such a big profile for the whole film but these children are amazing and should be praised for what they have done don't you think the whole story was so lovely because it was true and was someone's life after all that was shared with us all\",\n \"[BOS] big hair big boobs bad music and a giant safety pin these are the words to best describe this terrible movie i love cheesy horror movies and i've seen hundreds but this had got to be on of the worst ever made the plot is paper thin and ridiculous the acting is an abomination the script is completely laughable the best is the end showdown with the cop and how he worked out who the killer is it's just so damn terribly written the clothes are sickening and funny in equal [UNK] the hair is big lots of boobs [UNK] men wear those cut [UNK] shirts that show off their [UNK] sickening that men actually wore them and the music is just [UNK] trash that plays over and over again in almost every scene there is trashy music boobs and [UNK] taking away bodies and the gym still doesn't close for [UNK] all joking aside this is a truly bad film whose only charm is to look back on the disaster that was the 80's and have a good old laugh at how bad everything was back then\"]"
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 看看训练集的数据\n",
    "\n",
    "tokenizer.decode(train_data[:2], remove_bos=False, remove_eos=False, remove_pad=False)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据集与 DataLoader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T02:13:33.146038300Z",
     "start_time": "2024-05-02T02:13:27.453283100Z"
    }
   },
   "outputs": [],
   "source": [
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "class IMDBDataset(Dataset):\n",
    "    def __init__(self, data, labels, remain_length=True):\n",
    "        if remain_length: #字符串输出样本中，是否含有【BOS】和【EOS】，【PAD】\n",
    "            self.data = tokenizer.decode(data, remove_bos=False, remove_eos=False, remove_pad=False)\n",
    "        else:\n",
    "            # 缩减一下数据\n",
    "            self.data = tokenizer.decode(data)\n",
    "        self.labels = labels\n",
    "    \n",
    "    def __getitem__(self, index):\n",
    "        text = self.data[index]\n",
    "        label = self.labels[index]\n",
    "        return text, label\n",
    "    \n",
    "    def __len__(self):\n",
    "        return len(self.data)\n",
    "    \n",
    "    \n",
    "def collate_fct(batch):\n",
    "    text_list = [item[0].split() for item in batch]\n",
    "    label_list = [item[1] for item in batch]\n",
    "    # 这里使用 padding first\n",
    "    text_list = tokenizer.encode(text_list, padding_first=True).to(dtype=torch.int)\n",
    "    return text_list, torch.tensor(label_list).reshape(-1, 1).to(dtype=torch.float)\n",
    "\n",
    "\n",
    "# 用RNN，缩短序列长度\n",
    "train_ds = IMDBDataset(train_data, train_labels, remain_length=False)\n",
    "test_ds = IMDBDataset(test_data, test_labels, remain_length=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T02:13:37.966029100Z",
     "start_time": "2024-05-02T02:13:37.954033700Z"
    }
   },
   "outputs": [],
   "source": [
    "batch_size = 128\n",
    "train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True, collate_fn=collate_fct)\n",
    "test_dl = DataLoader(test_ds, batch_size=batch_size, shuffle=False, collate_fn=collate_fct)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 定义模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T02:47:40.904021100Z",
     "start_time": "2024-05-02T02:47:40.852042200Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=================================== 一层单向 RNN ===================================\n",
      "            embeding.weight             paramerters num: 160000\n",
      "            rnn.weight_ih_l0            paramerters num: 1024\n",
      "            rnn.weight_hh_l0            paramerters num: 4096\n",
      "             rnn.bias_ih_l0             paramerters num: 64\n",
      "             rnn.bias_hh_l0             paramerters num: 64\n",
      "              layer.weight              paramerters num: 4096\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n",
      "=================================== 一层双向 RNN ===================================\n",
      "            embeding.weight             paramerters num: 160000\n",
      "            rnn.weight_ih_l0            paramerters num: 1024\n",
      "            rnn.weight_hh_l0            paramerters num: 4096\n",
      "             rnn.bias_ih_l0             paramerters num: 64\n",
      "             rnn.bias_hh_l0             paramerters num: 64\n",
      "        rnn.weight_ih_l0_reverse        paramerters num: 1024\n",
      "        rnn.weight_hh_l0_reverse        paramerters num: 4096\n",
      "         rnn.bias_ih_l0_reverse         paramerters num: 64\n",
      "         rnn.bias_hh_l0_reverse         paramerters num: 64\n",
      "              layer.weight              paramerters num: 8192\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n",
      "=================================== 俩层单向 RNN ===================================\n",
      "            embeding.weight             paramerters num: 160000\n",
      "            rnn.weight_ih_l0            paramerters num: 1024\n",
      "            rnn.weight_hh_l0            paramerters num: 4096\n",
      "             rnn.bias_ih_l0             paramerters num: 64\n",
      "             rnn.bias_hh_l0             paramerters num: 64\n",
      "            rnn.weight_ih_l1            paramerters num: 4096\n",
      "            rnn.weight_hh_l1            paramerters num: 4096\n",
      "             rnn.bias_ih_l1             paramerters num: 64\n",
      "             rnn.bias_hh_l1             paramerters num: 64\n",
      "              layer.weight              paramerters num: 4096\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n"
     ]
    }
   ],
   "source": [
    "class RNN(nn.Module):\n",
    "    def __init__(self, embedding_dim=16, hidden_dim=64, vocab_size=vocab_size, num_layers=1, bidirectional=False):\n",
    "        super(RNN, self).__init__()\n",
    "        self.embeding = nn.Embedding(vocab_size, embedding_dim)\n",
    "        self.rnn = nn.RNN(embedding_dim, hidden_dim, num_layers=num_layers, batch_first=True, bidirectional=bidirectional)\n",
    "        self.layer = nn.Linear(hidden_dim * (2 if bidirectional else 1), hidden_dim)\n",
    "        self.fc = nn.Linear(hidden_dim, 1)\n",
    "\n",
    "    def forward(self, x):\n",
    "        # [bs, seq length]\n",
    "        x = self.embeding(x)\n",
    "        # [bs, seq length, embedding_dim] -> shape [bs, embedding_dim, seq length]\n",
    "        seq_output, final_hidden = self.rnn(x)\n",
    "        # [bs, seq length, hidden_dim], [bs,-1, hidden_dim]\n",
    "        x = seq_output[:, -1, :]\n",
    "        # 取最后一个时间步的输出 (这也是为什么要设置padding_first=True的原因)\n",
    "        x = self.layer(x)\n",
    "        x = self.fc(x)\n",
    "        return x\n",
    "    \n",
    "sample_inputs = torch.randint(0, vocab_size, (2, 128))\n",
    "    \n",
    "print(\"{:=^80}\".format(\" 一层单向 RNN \"))       \n",
    "for key, value in RNN().named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n",
    "\n",
    "    \n",
    "print(\"{:=^80}\".format(\" 单层双向 RNN \"))\n",
    "for key, value in RNN(bidirectional=True).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n",
    "\n",
    "    \n",
    "print(\"{:=^80}\".format(\" 双层单向 RNN \"))\n",
    "for key, value in RNN(num_layers=2).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=================================== 双层双向 RNN ===================================\n",
      "            embeding.weight             paramerters num: 160000\n",
      "            rnn.weight_ih_l0            paramerters num: 1024\n",
      "            rnn.weight_hh_l0            paramerters num: 4096\n",
      "             rnn.bias_ih_l0             paramerters num: 64\n",
      "             rnn.bias_hh_l0             paramerters num: 64\n",
      "        rnn.weight_ih_l0_reverse        paramerters num: 1024\n",
      "        rnn.weight_hh_l0_reverse        paramerters num: 4096\n",
      "         rnn.bias_ih_l0_reverse         paramerters num: 64\n",
      "         rnn.bias_hh_l0_reverse         paramerters num: 64\n",
      "            rnn.weight_ih_l1            paramerters num: 8192\n",
      "            rnn.weight_hh_l1            paramerters num: 4096\n",
      "             rnn.bias_ih_l1             paramerters num: 64\n",
      "             rnn.bias_hh_l1             paramerters num: 64\n",
      "        rnn.weight_ih_l1_reverse        paramerters num: 8192\n",
      "        rnn.weight_hh_l1_reverse        paramerters num: 4096\n",
      "         rnn.bias_ih_l1_reverse         paramerters num: 64\n",
      "         rnn.bias_hh_l1_reverse         paramerters num: 64\n",
      "              layer.weight              paramerters num: 8192\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n"
     ]
    }
   ],
   "source": [
    "print(\"{:=^80}\".format(\" 双层双向 RNN \"))\n",
    "for key, value in RNN(num_layers=2, bidirectional=True).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-02T03:27:49.428065Z",
     "start_time": "2024-05-02T03:27:49.371096900Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([0, 4, 1, 2])\n"
     ]
    }
   ],
   "source": [
    "#给我一个3行4列的ndarray\n",
    "sample_inputs = torch.randint(0, 10, (3, 4))\n",
    "print(sample_inputs[0,:])"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-02T02:45:30.029214Z",
     "start_time": "2024-05-02T02:45:30.000229300Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "outputs": [
    {
     "data": {
      "text/plain": "1024"
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "16*64"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-02T02:33:07.221837800Z",
     "start_time": "2024-05-02T02:33:07.192854600Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "outputs": [
    {
     "data": {
      "text/plain": "4096"
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "64*64"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-02T02:33:13.689732900Z",
     "start_time": "2024-05-02T02:33:13.678716500Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "outputs": [
    {
     "data": {
      "text/plain": "8192"
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "128*64"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-02T03:15:55.267051100Z",
     "start_time": "2024-05-02T03:15:55.224073500Z"
    }
   }
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-12-07T09:04:19.725273600Z",
     "start_time": "2023-12-07T09:04:19.673302600Z"
    }
   },
   "outputs": [],
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in dataloader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向计算\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)         # 验证集损失\n",
    "        loss_list.append(loss.item())\n",
    "        # 二分类\n",
    "        preds = logits > 0\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())\n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "        \n",
    "    acc = accuracy_score(label_list, pred_list)\n",
    "    return np.mean(loss_list), acc\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### TensorBoard 可视化\n",
    "\n",
    "\n",
    "训练过程中可以使用如下命令启动tensorboard服务。\n",
    "\n",
    "```shell\n",
    "tensorboard \\\n",
    "    --logdir=runs \\     # log 存放路径\n",
    "    --host 0.0.0.0 \\    # ip\n",
    "    --port 8848         # 端口\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-12-07T09:04:19.779322Z",
     "start_time": "2023-12-07T09:04:19.726271400Z"
    }
   },
   "outputs": [],
   "source": [
    "from torch.utils.tensorboard import SummaryWriter\n",
    "\n",
    "\n",
    "class TensorBoardCallback:\n",
    "    def __init__(self, log_dir, flush_secs=10):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            log_dir (str): dir to write log.\n",
    "            flush_secs (int, optional): write to dsk each flush_secs seconds. Defaults to 10.\n",
    "        \"\"\"\n",
    "        self.writer = SummaryWriter(log_dir=log_dir, flush_secs=flush_secs)\n",
    "\n",
    "    def draw_model(self, model, input_shape):\n",
    "        self.writer.add_graph(model, input_to_model=torch.randn(input_shape))\n",
    "        \n",
    "    def add_loss_scalars(self, step, loss, val_loss):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/loss\", \n",
    "            tag_scalar_dict={\"loss\": loss, \"val_loss\": val_loss},\n",
    "            global_step=step,\n",
    "            )\n",
    "        \n",
    "    def add_acc_scalars(self, step, acc, val_acc):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/accuracy\",\n",
    "            tag_scalar_dict={\"accuracy\": acc, \"val_accuracy\": val_acc},\n",
    "            global_step=step,\n",
    "        )\n",
    "        \n",
    "    def add_lr_scalars(self, step, learning_rate):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/learning_rate\",\n",
    "            tag_scalar_dict={\"learning_rate\": learning_rate},\n",
    "            global_step=step,\n",
    "            \n",
    "        )\n",
    "    \n",
    "    def __call__(self, step, **kwargs):\n",
    "        # add loss\n",
    "        loss = kwargs.pop(\"loss\", None)\n",
    "        val_loss = kwargs.pop(\"val_loss\", None)\n",
    "        if loss is not None and val_loss is not None:\n",
    "            self.add_loss_scalars(step, loss, val_loss)\n",
    "        # add acc\n",
    "        acc = kwargs.pop(\"acc\", None)\n",
    "        val_acc = kwargs.pop(\"val_acc\", None)\n",
    "        if acc is not None and val_acc is not None:\n",
    "            self.add_acc_scalars(step, acc, val_acc)\n",
    "        # add lr\n",
    "        learning_rate = kwargs.pop(\"lr\", None)\n",
    "        if learning_rate is not None:\n",
    "            self.add_lr_scalars(step, learning_rate)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Save Best\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-12-07T09:04:19.791316800Z",
     "start_time": "2023-12-07T09:04:19.755336900Z"
    }
   },
   "outputs": [],
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "        \n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "        \n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "        \n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Early Stop"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-12-07T09:04:19.791316800Z",
     "start_time": "2023-12-07T09:04:19.779322Z"
    }
   },
   "outputs": [],
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute \n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = -1\n",
    "        self.counter = 0\n",
    "        \n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter \n",
    "            self.counter = 0\n",
    "        else: \n",
    "            self.counter += 1\n",
    "            \n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "outputs": [],
   "source": [
    "input = torch.randn(3, requires_grad=True)\n",
    "target = torch.empty(3).random_(2)\n",
    "loss1 = F.binary_cross_entropy_with_logits(input, target)\n",
    "loss1.backward()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-02T02:55:44.473814700Z",
     "start_time": "2024-05-02T02:55:44.413855800Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "outputs": [
    {
     "data": {
      "text/plain": "tensor([-0.8001,  0.3879,  0.2289], requires_grad=True)"
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "input"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-02T02:55:57.618987300Z",
     "start_time": "2024-05-02T02:55:57.571020100Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "outputs": [
    {
     "data": {
      "text/plain": "tensor([1., 0., 0.])"
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "target"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-02T02:56:06.605387700Z",
     "start_time": "2024-05-02T02:56:06.589376Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "outputs": [
    {
     "data": {
      "text/plain": "tensor(0.9637, grad_fn=<BinaryCrossEntropyWithLogitsBackward0>)"
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "loss1"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-02T02:56:34.004070400Z",
     "start_time": "2024-05-02T02:56:33.979083100Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-12-07T09:21:46.502713600Z",
     "start_time": "2023-12-07T09:04:19.791316800Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": "  0%|          | 0/3920 [00:00<?, ?it/s]",
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "92989e96f6c64de79be225b226b634a2"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Early stop at epoch 14 / global_step 2744\n"
     ]
    }
   ],
   "source": [
    "# 训练\n",
    "def training(\n",
    "    model, \n",
    "    train_loader, \n",
    "    val_loader, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=None,\n",
    "    early_stop_callback=None,\n",
    "    eval_step=500,\n",
    "    ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "    \n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits = model(datas)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits, labels)\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                preds = logits > 0 # 二分类,logits大于0的为1类别，否则为0类别\n",
    "            \n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())    \n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "                \n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"acc\": acc, \"step\": global_step\n",
    "                })\n",
    "                \n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "                    \n",
    "                    # 1. 使用 tensorboard 可视化\n",
    "                    if tensorboard_callback is not None:\n",
    "                        tensorboard_callback(\n",
    "                            global_step, \n",
    "                            loss=loss, val_loss=val_loss,\n",
    "                            acc=acc, val_acc=val_acc,\n",
    "                            lr=optimizer.param_groups[0][\"lr\"],\n",
    "                            )\n",
    "                \n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(val_acc)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "                    \n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "        \n",
    "    return record_dict\n",
    "        \n",
    "\n",
    "epoch = 20\n",
    "\n",
    "model = RNN()\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失 (但是二分类)\n",
    "loss_fct = F.binary_cross_entropy_with_logits\n",
    "# 2. 定义优化器 采用 adam\n",
    "# Optimizers specified in the torch.optim package\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "# 1. tensorboard 可视化\n",
    "if not os.path.exists(\"runs\"):\n",
    "    os.mkdir(\"runs\")\n",
    "tensorboard_callback = TensorBoardCallback(\"runs/imdb-rnn\")\n",
    "# tensorboard_callback.draw_model(model, [1, MAX_LENGTH])\n",
    "# 2. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(\"checkpoints/imdb-rnn\", save_step=len(train_dl), save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=10)\n",
    "\n",
    "model = model.to(device)\n",
    "record = training(\n",
    "    model, \n",
    "    train_dl, \n",
    "    test_dl, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=tensorboard_callback,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_dl)\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-12-07T09:21:48.454603700Z",
     "start_time": "2023-12-07T09:21:46.509709300Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 720x360 with 2 Axes>",
      "image/png": "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cYXnfg8//DC//OUvEUIwbdo0HnnkEQ4fPsznP/95du7cCcB9993HWWed1fVr9tErEEsaP93GZMVMoylhM57UqQxDcqQpSkleiISe3K6bjL1M8I0sH13G48v28e2n1rL1J+/vNr/7ex3XXnstX/3qV62X5OOPP87LL7/Ml7/8Zfr06cORI0c488wzufzyyx1hy+3hnnvuQQjBu+++y/79+7n44ovZunUr999/P1/5ylf4+Mc/TiwWQ9d1XnjhBYYOHcrzzz8PmIWFffQO5LL/5Ofn88wzz6Ttt3HjRn7yk5+waNEiysvLrULPX/7ylznvvPN45pln0HWdpqambr9eHycOFHOU6CYGSWmyEoY3kxVLGOhhaRl5Md1nsnz0Mvz0xU0ANEbi9C/OO86t6Wa0wzi50ZqjZJMzZ86kurqaAwcOUFNTQ1lZGYMHD+ZrX/sab731FpqmsX//fg4fPszgwYOzPu7ChQv50pe+BMCECRMYNWoUW7duZd68edx1111UVVXxkY98hHHjxjF16lS+8Y1v8P/+3//jgx/8IOecc06Xr+s9CVsfylX/aA+57D9SSr773e+m7bdgwQKuvvpqysvLAejXrx8ACxYs4OGHHwYgEAhQWlravRfr44SCEpwnulmTpdsYKvXRkBBNGBiGtM4f940sH70Nqmt3hEHx0XFcffXVPPnkkxw6dIhrr72WRx99lJqaGlasWEEoFGL06NFEIpGcnOtjH/sYc+fO5fnnn+eyyy7jj3/8IxdccAErV67khRde4Hvf+x4XXnghP/jBD9o/mI8TArnqP93Z73ycfFAMUne56azjezBZhmEyWYZMMVnxHnYX+r4dHzmDb2J1L6699loee+wxnnzySa6++moaGhoYOHAgoVCIN954gz179nT4mOeccw6PPvooAFu3bmXv3r2cdtpp7Ny5k7Fjx/LlL3+ZK664grVr13LgwAEKCwv5xCc+wbe+9S1WrlyZ60v00Y3IVf/JtN8FF1zAE088QW1tLYDlLrzwwgu57777ALMGou9mfm9BGT/dpclKnceuyUqdM5Yw0GWKweppJss3snx0GSoktocjY99zmDx5Mo2NjQwbNowhQ4bw8Y9/nOXLlzN16lQefvhhJkyY0OFjfvGLX8QwDM4880yuvfZa/vrXv5KXl8fjjz/OlClTmDFjBuvXr+eTn/wk69at44wz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\n"
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "#画线要注意的是损失是不一定在零到1之间的\n",
    "def plot_learning_curves(record_dict, sample_step=500):\n",
    "    # build DataFrame\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    # plot\n",
    "    fig_num = len(train_df.columns)\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):    \n",
    "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
    "        axs[idx].grid()\n",
    "        axs[idx].legend()\n",
    "        # axs[idx].set_xticks(range(0, train_df.index[-1], 5000))\n",
    "        # axs[idx].set_xticklabels(map(lambda x: f\"{int(x/1000)}k\", range(0, train_df.index[-1], 5000)))\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "    \n",
    "    plt.show()\n",
    "\n",
    "plot_learning_curves(record, sample_step=10)  #横坐标是 steps"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-12-07T09:22:04.587411800Z",
     "start_time": "2023-12-07T09:21:48.456602300Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     0.5776\n",
      "accuracy: 0.7137\n"
     ]
    }
   ],
   "source": [
    "# dataload for evaluating\n",
    "\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(\"checkpoints/imdb-rnn/best.ckpt\", map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, test_dl, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pytorch",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.8"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
